package com.novunda.platform.security.qrcode;

import com.novunda.platform.common.context.SpringContextHolder;
import com.novunda.platform.common.utils.StringUtil;
import com.novunda.platform.entities.User;
import com.novunda.platform.security.CommonAuthenticationFilter;
import com.novunda.platform.security.LoginException;
import com.novunda.platform.security.LoginTypeEnum;
import com.novunda.platform.security.NovUsernamePasswordToken;
import com.novunda.platform.services.UserService;
import com.novunda.tca.tdk.domain.ResourceDataInfo;
import com.novunda.tca.tdk.http.OltuURLConnectionClient;
import com.novunda.tca.tdk.utils.ConfigResource;
import com.novunda.tca.tdk.utils.GsonUtils;
import org.apache.oltu.oauth2.client.OAuthClient;
import org.apache.oltu.oauth2.client.request.OAuthClientRequest;
import org.apache.oltu.oauth2.client.response.OAuthAccessTokenResponse;
import org.apache.oltu.oauth2.client.response.OAuthResourceResponse;
import org.apache.oltu.oauth2.common.OAuth;
import org.apache.oltu.oauth2.common.exception.OAuthProblemException;
import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
import org.apache.oltu.oauth2.common.message.types.GrantType;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.util.regex.Pattern;

/**
 * 二维码登陆拦截器
 *
 * @author linfeng
 * @since 2016/9/20.
 */
public class QrCodeAuthenticatingFilter extends CommonAuthenticationFilter {

    private static final Logger log = LoggerFactory.getLogger(QrCodeAuthenticatingFilter.class);

    private static final Pattern COMPILE_SPLIT = Pattern.compile(":::");

    private UserService userService;

    private final String code = "code";

    public QrCodeAuthenticatingFilter(String loginUrl) {
        setLoginUrl(loginUrl);
    }

    protected String getCode(ServletRequest request) {
        return WebUtils.getCleanParam(request, code);
    }

    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {

        logout(request, response);
        return getResourceData(request);
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        return executeLogin(request, response);
    }

    /**
     * 获得资源
     *
     * @param request request
     * @return 登陆token
     * @throws OAuthSystemException
     * @throws OAuthProblemException
     */
    private UsernamePasswordToken getResourceData(ServletRequest request) {

        String host = getHost(request);
        String code = getCode(request);

        OAuthClient oAuthClient = new OAuthClient(new OltuURLConnectionClient());

        OAuthResourceResponse resourceResponse = null;
        OAuthClientRequest accessTokenRequest = null;
        try {
            accessTokenRequest = OAuthClientRequest
                    .tokenLocation(ConfigResource.accessURI)
                    .setGrantType(GrantType.AUTHORIZATION_CODE)
                    .setClientId(ConfigResource.clientId)
                    .setClientSecret(ConfigResource.clientSecret)
                    .setCode(code)
                    .setRedirectURI(ConfigResource.webRedirectUrl) // 随便传的
                    .buildQueryMessage();


            OAuthAccessTokenResponse oAuthResponse = oAuthClient.accessToken(accessTokenRequest, OAuth.HttpMethod.POST);

            String accessToken = oAuthResponse.getAccessToken();

            OAuthClientRequest userInfoRequest = OAuthClientRequest
                    .tokenLocation(ConfigResource.resourceURI)
                    .setParameter("client_id", ConfigResource.clientId)
                    .setParameter("access_token", accessToken)
                    .buildQueryMessage();

            resourceResponse = oAuthClient.resource(userInfoRequest, OAuth.HttpMethod.GET, OAuthResourceResponse.class);

        } catch (OAuthSystemException | OAuthProblemException e) {
            throw new LoginException("资源获取失败", e);
        }

        String content = resourceResponse.getBody();
        ResourceDataInfo resourceDataInfo = GsonUtils.getInstance().fromJson(content, ResourceDataInfo.class);
        // 判断授权资源是否为空
        if (resourceDataInfo == null) {
            throw new LoginException("资源获取失败");
        }

        User user;
        // 判断验证信息是否为空
        String qrdata = resourceDataInfo.getQrdata();
        if (StringUtil.isEmpty(qrdata)) {
            String validaData = resourceDataInfo.getValidationData();
            if (StringUtil.isEmpty(validaData)) {
                throw new LoginException("资源获取失败");
            }
            if ("|".equals(validaData)) {
                throw new LoginException("账号不存在");
            }
            String username = validaData.split("\\|")[0];
            user = getUserService().findByLoginName(username);
            // 判断用户是否存在
            if (user == null) {
                throw new LoginException("账号不存在");
            }
            // 判断账号是否被冻结
            if (user.getState() == 2) {
                throw new LoginException("账号被冻结");
            }
        } else {
            //获取户名
            String username = COMPILE_SPLIT.split(qrdata)[0];
            user = getUserService().findByLoginName(username);
            // 判断用户是否存在
            if (user == null) {
                throw new LoginException("账号不存在");
            }
            // 判断账号是否被冻结
            if (user.getState() == 2) {
                throw new LoginException("账号被冻结");
            }
            if ("1".equals(user.getDelFlag())) {
                throw new LoginException("账号被删除");
            }
            user.setBindStatus(1);
            user.setUuid(null);
            userService.saveUser(user);
        }
        String password = user.getPassword();
        // 判断密码是否为空
        password = password == null ? "" : password;
        return new NovUsernamePasswordToken(user.getLoginName(), password.toCharArray(), host, LoginTypeEnum.QRCODE);

    }

    /**
     * 获取用户对象
     */
    public UserService getUserService() {
        if (userService == null) {
            userService = SpringContextHolder.getBean("userService");
        }
        return userService;
    }

}
